home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 July: Mac OS SDK / Dev.CD Jul 00 SDK2.toast / Development Kits / Hardware / Mac OS USB DDK / Mac OS USB DDK 1.4.1 / Examples / USBSampleStorageDriver / StorageClassDriver / StorageClassBulkProtocol.c next >
Encoding:
C/C++ Source or Header  |  2000-04-25  |  16.9 KB  |  616 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        StorageClassBulkProtocol.c
  3.  
  4.     Contains:    All code specific to handling the Bulk Only Protocol
  5.  
  6.     Version:    1.3
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9. */
  10. #include <DriverServices.h>
  11.  
  12. #include "StorageClassBulkProtocol.h"
  13.  
  14. // All definitions and structures for the Bulk Only Command Block Wrapper (CBW)
  15. #define kCommandBlockWrapperSignature    'USBC'
  16. #define kByteCountOfCBW        31
  17.  
  18. struct StorageBulkOnlyCBW
  19. {
  20.     UInt32        cbwSignature;
  21.     UInt32        cbwTag;
  22.     UInt32        cbwTransferLength;
  23.     UInt8        cbwFlags;
  24.     UInt8        cbwLUN;                    // Bits 0-3: LUN, 4-7: Reserved
  25.     UInt8        cbwCDBLength;            // Bits 0-4: CDB Length, 5-7: Reserved
  26.     UInt8        cbwCDB[kUSBStorageMaxCDBSize];
  27.     UInt8        cbwBulkPad[4];
  28. };
  29.  
  30. typedef struct StorageBulkOnlyCBW    StorageBulkOnlyCBW;
  31. typedef    StorageBulkOnlyCBW             *StorageBulkOnlyCBWPtr;
  32.  
  33. enum
  34. {
  35.     kCBWFlagsDataOut    = 0x00,
  36.     kCBWFlagsDataIn        = 0x80
  37. };
  38.  
  39. // All definitions and structures for the Bulk Only Command Status Wrapper (CSW)
  40. #define kCommandStatusWrapperSingature    'USBS'
  41. #define kByteCountOfCSW        13
  42.  
  43. struct    StorageBulkOnlyCSW
  44. {
  45.     UInt32        cswSignature;
  46.     UInt32        cswTag;
  47.     UInt32        cswDataResidue;
  48.     UInt8        cswStatus;
  49. };
  50.  
  51. typedef struct StorageBulkOnlyCSW    StorageBulkOnlyCSW;
  52. typedef    StorageBulkOnlyCSW             *StorageBulkOnlyCSWPtr;
  53.  
  54. enum
  55. {
  56.     kCSWCommandPassedError     = 0x00,        // No error occurred
  57.     kCSWCommandFailedError    = 0x01,        // An error occurred ( probably a bad command or parameter )
  58.     kCSWPhaseError            = 0x02        // A transfer was performed in the wrong sequence
  59. };
  60.  
  61. // All definitions and structures used by this module
  62. struct StorageClassBulkOnlyPB 
  63. {
  64.     USBPB                            usbPB;
  65.     StorageBulkOnlyCBW                cbw;
  66.     StorageBulkOnlyCSW                csw;
  67.     UInt8                            GetStatusBuffer[2];    // 2 bytes as specified in the USB spec
  68.     Boolean                            busy;
  69.     UInt32                            flags;                // Flags from StorageClassRequest pb
  70.     UInt32                            currentSGElement;    // Scatter Gather element currently being transferred
  71.     UInt32                            currentSGCount;        // Scatter Gather element currently being transferred
  72.     StorageExecuteCommandPBPtr        userPBPtr;
  73. };
  74. typedef struct StorageClassBulkOnlyPB    StorageClassBulkOnlyPB;
  75. typedef    StorageClassBulkOnlyPB             *StorageClassBulkOnlyPBPtr;
  76.  
  77. // Bulk Only State Machine States
  78. enum
  79. {
  80.     kBulkOnlyCommandSent = 1,
  81.     kBulkOnlyBulkIOComplete,
  82.     kBulkOnlyCheckBulkStall,
  83.     kBulkOnlyClearBulkStall,
  84.     kBulkOnlyStatusReceived,
  85.     kBulkOnlyStatusReceived2ndTime,
  86.     kBulkOnlyResetCompleted,
  87.     kBulkOnlyClearBulkInCompleted,
  88.     kBulkOnlyClearBulkOutCompleted
  89. };
  90.  
  91. static    StorageClassBulkOnlyPB        gBulkCommandPB;                    // Used only by StorageClassDriverExecuteCommand
  92. static     UInt32                         bulkOnlyTag = 1;                // Count used to identify a Bulk Only command
  93.  
  94. // Bulk Only function protocols
  95. static OSStatus SendCBWPacket(StorageExecuteCommandPBPtr cmdPBPtr, StorageBulkOnlyCBWPtr theCBW, USBPB* usbPB);
  96. static OSStatus ReceiveCSWPacket(StorageBulkOnlyCSWPtr theCSW, USBPB* usbPB, UInt32 nextState);
  97. static OSStatus    BulkDeviceReset( USBPB* usbPB );
  98. static void BulkOnlyExecuteCommandCompletion(USBPB* usbPB);
  99.  
  100. OSStatus StorageClassBulkOnlyAbortCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  101. {
  102.     OSStatus err = noErr;
  103.     
  104.     if (( gBulkCommandPB.busy == true ) && ( cmdPBPtr == gBulkCommandPB.userPBPtr ))
  105.     {
  106.         // If there is a command pending, and the command is the one we want to
  107.         // abort, go ahead and do it.
  108.         USBReference pipeRef;
  109.         
  110.         switch ( gBulkCommandPB.usbPB.usbRefcon )
  111.         {
  112.             case kBulkOnlyCommandSent:
  113.             {
  114.                 pipeRef = GetBulkInPipeRef();
  115.             }
  116.             break;
  117.             
  118.             case kBulkOnlyBulkIOComplete:
  119.             {
  120.                 if (gBulkCommandPB.flags & kStorageDataIn)
  121.                 {
  122.                     pipeRef = GetBulkInPipeRef();
  123.                 }
  124.                 else
  125.                 {
  126.                     pipeRef = GetBulkOutPipeRef();
  127.                 }
  128.             }
  129.             break;
  130.             
  131.             case kBulkOnlyStatusReceived:
  132.             case kBulkOnlyStatusReceived2ndTime:
  133.             {
  134.                 pipeRef = GetBulkInPipeRef();
  135.             }
  136.             break;
  137.             
  138.             default:
  139.             {
  140.                 pipeRef = GetInterfaceRef();
  141.             }
  142.             break;
  143.         }
  144.  
  145.         err = USBAbortPipeByReference(pipeRef);
  146.     }
  147.     else
  148.     {
  149.         err = abortErr;
  150.     }
  151.  
  152.     return err;
  153. }
  154.  
  155. // Prepare the Command Block Wrapper packet for Bulk Only Protocol
  156. OSStatus SendCBWPacket(StorageExecuteCommandPBPtr cmdPBPtr, StorageBulkOnlyCBWPtr theCBW, USBPB* usbPB)
  157. {
  158.     theCBW->cbwSignature = kCommandBlockWrapperSignature;
  159.     theCBW->cbwTag = bulkOnlyTag++;
  160.     theCBW->cbwTransferLength = HostToUSBLong(cmdPBPtr->expectedCount);
  161.     if (cmdPBPtr->flags & kStorageDataIn)
  162.     {
  163.         theCBW->cbwFlags = kCBWFlagsDataIn;
  164.     }
  165.     else if (cmdPBPtr->flags & kStorageDataOut)
  166.     {
  167.         theCBW->cbwFlags = kCBWFlagsDataOut;
  168.     }
  169.     else
  170.     {
  171.         theCBW->cbwFlags = 0;
  172.     }
  173.  
  174.     theCBW->cbwLUN = 0;                                        // Bits 0-3: LUN, 4-7: Reserved
  175.     theCBW->cbwCDBLength = kUSBStorageMaxCDBSize;            // Bits 0-4: CDB Length, 5-7: Reserved
  176.     BlockCopy(&cmdPBPtr->cdb[0], theCBW->cbwCDB, kUSBStorageMaxCDBSize);
  177.  
  178.     InitParamBlock( GetBulkOutPipeRef(), usbPB);
  179.  
  180.     usbPB->usbReqCount         = kByteCountOfCBW;
  181.     usbPB->usbRefcon         = kBulkOnlyCommandSent;
  182.     usbPB->usbActCount         = 0;
  183.     usbPB->usbBuffer         = theCBW;
  184.     usbPB->usbCompletion     = (USBCompletion)BulkOnlyExecuteCommandCompletion;
  185.     usbPB->usbFlags         |= kUSBTimeout;        // If the device doesn't ack the CBW, allow a time out
  186.     usbPB->usbFrame         = 5000;                // We want a 5 second timeout (5000 1ms USB Frames)
  187.     
  188.     return USBBulkWrite( usbPB );
  189. }
  190.  
  191. // Prepare the Command Status Wrapper packet for Bulk Only Protocol
  192. OSStatus ReceiveCSWPacket(StorageBulkOnlyCSWPtr theCSW, USBPB* usbPB, UInt32 nextState)
  193. {
  194.     InitParamBlock( GetBulkInPipeRef(), usbPB);
  195.  
  196.     usbPB->usbReqCount         = kByteCountOfCSW;
  197.     usbPB->usbRefcon         = nextState;
  198.     usbPB->usbActCount         = 0;
  199.     usbPB->usbBuffer         = theCSW;
  200.     usbPB->usbCompletion     = (USBCompletion)BulkOnlyExecuteCommandCompletion;
  201.     
  202.     return USBBulkRead( usbPB );
  203. }
  204.  
  205. OSStatus BulkDeviceReset( USBPB* usbPB )
  206. {
  207.     InitParamBlock( GetInterfaceRef(), usbPB);
  208.  
  209.     usbPB->usb.cntl.BMRequestType     = USBMakeBMRequestType(kUSBNone, kUSBClass, kUSBInterface);            
  210.     usbPB->usb.cntl.BRequest         = 0xFF;
  211.     usbPB->usb.cntl.WValue             = 0;
  212.     usbPB->usb.cntl.WIndex             = 0;
  213.     
  214.     usbPB->usbFlags         = kUSBNo5SecTimeout | kUSBAddressRequest;
  215.  
  216.     usbPB->usbReqCount         = 0;
  217.     usbPB->usbRefcon         = kBulkOnlyResetCompleted;
  218.     usbPB->usbActCount         = 0;
  219.     usbPB->usbBuffer         = nil;
  220.     usbPB->usbCompletion     = (USBCompletion)BulkOnlyExecuteCommandCompletion;
  221.  
  222.     return USBDeviceRequest(usbPB);
  223. }
  224.  
  225. // All Bulk Only protocol device requests come through here
  226. OSStatus StorageClassBulkOnlyExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  227. {
  228.     OSStatus            myErr;
  229.     
  230.     // check if we already have a read in progress, if so return error.
  231.     if (gBulkCommandPB.busy == true)
  232.     {
  233.         cmdPBPtr->status = kCommandBusyError;
  234.         return kCommandBusyError;
  235.     }
  236.     
  237.     BlockZero(&gBulkCommandPB, sizeof(StorageClassBulkOnlyPB));
  238.         
  239.     gBulkCommandPB.busy = true;
  240.  
  241.     // Get a local copy of the callers cdb
  242.     BlockCopy(&cmdPBPtr->cdb[0], &gBulkCommandPB.cbw.cbwCDB[0], kUSBStorageMaxCDBSize);
  243.     
  244.     gBulkCommandPB.flags = cmdPBPtr->flags;
  245.     
  246.     gBulkCommandPB.userPBPtr = (StorageExecuteCommandPBPtr) cmdPBPtr;                // Save the ptr to the callers PB
  247.     
  248.     // Clear out the sutosense is valid field, currently not used by Bulk Only protocol
  249.     cmdPBPtr->autoStatusIsValid = false;
  250.  
  251.     myErr = SendCBWPacket(cmdPBPtr, &gBulkCommandPB.cbw, &gBulkCommandPB.usbPB);
  252.     if (myErr != kRequestPending )
  253.     {
  254.         // The command completed immediately ( we probably got an error )
  255.         // clear the PB's busy flag and return
  256.         gBulkCommandPB.busy = false;
  257.     }
  258.  
  259.     cmdPBPtr->status = myErr;
  260.     return myErr;
  261. }
  262.  
  263. void BulkOnlyExecuteCommandCompletion(USBPB* usbPB)
  264. {
  265.     StorageExecuteCommandPBPtr    cmdPBPtr;
  266.     StorageClassBulkOnlyPBPtr    bulkPBPtr;
  267.  
  268.     // Get the command's Bulk PB
  269.     bulkPBPtr = (StorageClassBulkOnlyPBPtr) usbPB;
  270.     
  271.     // Retrieve the callers pb
  272.     cmdPBPtr = (StorageExecuteCommandPBPtr) bulkPBPtr->userPBPtr;
  273.  
  274.     switch(usbPB->usbRefcon)
  275.     {
  276.         case kBulkOnlyCommandSent:
  277.         {
  278.             // If there is to be no data transfer then we are done and can return to the caller
  279.             if (bulkPBPtr->flags & kStorageNoData)
  280.             {
  281.                 if (usbPB->usbStatus != noErr)
  282.                 {
  283.                     cmdPBPtr->status = usbPB->usbStatus;
  284.                 }
  285.                 else
  286.                 {
  287.                     // Bulk transfer is done, get the Command Status Wrapper from the device
  288.                     cmdPBPtr->status = ReceiveCSWPacket(&bulkPBPtr->csw, usbPB, kBulkOnlyStatusReceived);
  289.                 }
  290.                 
  291.                 // There is no data to be transfered
  292.                 break;
  293.             }
  294.             
  295.             if (usbPB->usbStatus != noErr)
  296.             {
  297.                 // An error occurred, probably a timeout error,
  298.                 // and the command was not successfully sent to the device.
  299.                 cmdPBPtr->status = usbPB->usbStatus;
  300.                 break;
  301.             }
  302.  
  303.             // Setup the usb pb for either bulk in or out
  304.             if (bulkPBPtr->flags & kStorageDataIn)
  305.             {
  306.                 InitParamBlock( GetBulkInPipeRef(), usbPB);
  307.             }
  308.             else if (bulkPBPtr->flags & kStorageDataOut)
  309.             {
  310.                 InitParamBlock( GetBulkOutPipeRef(), usbPB);
  311.             }
  312.  
  313.             if (bulkPBPtr->flags & kStorageSGBuffer)
  314.             {
  315.                 // We have a scatter-gather transfer 
  316.                 USBSGListPtr        theSGList;
  317.                 USBSGElementPtr        currentSGElement;
  318.                 
  319.                 bulkPBPtr->currentSGElement = 0;
  320.                 bulkPBPtr->currentSGCount = 0;
  321.                 theSGList = (USBSGListPtr) cmdPBPtr->userBuffer;
  322.                 currentSGElement = &theSGList->sgElementList[0];
  323.                 if ( currentSGElement->SGCount > kUSBMaxBulkTransfer )
  324.                 {
  325.                     usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  326.                 }
  327.                 else
  328.                 {
  329.                     usbPB->usbReqCount     = currentSGElement->SGCount;
  330.                 }
  331.                 
  332.                 usbPB->usbBuffer         = currentSGElement->SGAddr;
  333.             }
  334.             else
  335.             {
  336.                 // We have a single buffer transfer 
  337.                 if ( cmdPBPtr->expectedCount > kUSBMaxBulkTransfer )
  338.                 {
  339.                     usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  340.                 }
  341.                 else
  342.                 {
  343.                     usbPB->usbReqCount     = cmdPBPtr->expectedCount;
  344.                 }
  345.                 
  346.                 usbPB->usbBuffer         = cmdPBPtr->userBuffer;
  347.             }
  348.  
  349.             usbPB->usbRefcon         = kBulkOnlyBulkIOComplete;
  350.             usbPB->usbActCount         = 0;
  351.             usbPB->usbCompletion     = (USBCompletion)BulkOnlyExecuteCommandCompletion;
  352.             
  353.             // Start a bulk in or out transaction
  354.             if (bulkPBPtr->flags & kStorageDataIn)
  355.             {
  356.                 cmdPBPtr->status = USBBulkRead(&bulkPBPtr->usbPB);
  357.             }
  358.             else if (bulkPBPtr->flags & kStorageDataOut)
  359.             {
  360.                 cmdPBPtr->status = USBBulkWrite(&bulkPBPtr->usbPB);
  361.             }
  362.         }
  363.         break;
  364.         
  365.         case kBulkOnlyBulkIOComplete:
  366.         {
  367.             cmdPBPtr->actualCount     +=    usbPB->usbActCount;            // Update the users byte count
  368.             cmdPBPtr->status         =    usbPB->usbStatus;            // and status
  369.             
  370.             if (usbPB->usbStatus == noErr)
  371.             {
  372.                 if (( cmdPBPtr->actualCount != cmdPBPtr->expectedCount) && ( usbPB->usbActCount == usbPB->usbReqCount ))
  373.                 {
  374.                     // If we have not yet transfered all the data and there are no Errors and we did not get a short packet.
  375.                     // Setup the usb pb for either bulk in or out
  376.                     UInt32 actCount = usbPB->usbActCount;
  377.                 
  378.                     if (bulkPBPtr->flags & kStorageDataIn)
  379.                     {
  380.                         InitParamBlock( GetBulkInPipeRef(), usbPB);
  381.                     }
  382.                     else if (bulkPBPtr->flags & kStorageDataOut)
  383.                     {
  384.                         InitParamBlock( GetBulkOutPipeRef(), usbPB);
  385.                     }
  386.         
  387.                     if (bulkPBPtr->flags & kStorageSGBuffer)
  388.                     {
  389.                         // We have a scatter-gather transfer 
  390.                         USBSGListPtr        theSGList;
  391.                         USBSGElementPtr        currentSGElement;
  392.                         
  393.                         bulkPBPtr->currentSGCount += actCount;
  394.                         theSGList = (USBSGListPtr) cmdPBPtr->userBuffer;
  395.                         currentSGElement = &theSGList->sgElementList[bulkPBPtr->currentSGElement];
  396.                         
  397.                         if ( bulkPBPtr->currentSGCount >= currentSGElement->SGCount)
  398.                         {
  399.                             // Move on to next SG segment
  400.                             bulkPBPtr->currentSGElement++;
  401.                             currentSGElement = &theSGList->sgElementList[bulkPBPtr->currentSGElement];
  402.                             bulkPBPtr->currentSGCount = 0;
  403.                             if ( currentSGElement->SGCount > kUSBMaxBulkTransfer )
  404.                             {
  405.                                 usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  406.                             }
  407.                             else
  408.                             {
  409.                                 usbPB->usbReqCount     = currentSGElement->SGCount;
  410.                             }
  411.                             
  412.                             usbPB->usbBuffer         = currentSGElement->SGAddr;
  413.                         }
  414.                         else
  415.                         {
  416.                             if ( (currentSGElement->SGCount - bulkPBPtr->currentSGCount) > kUSBMaxBulkTransfer )
  417.                             {
  418.                                 usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  419.                             }
  420.                             else
  421.                             {
  422.                                 usbPB->usbReqCount     = (currentSGElement->SGCount - bulkPBPtr->currentSGCount);
  423.                             }
  424.                             
  425.                             usbPB->usbBuffer         = currentSGElement->SGAddr + bulkPBPtr->currentSGCount;
  426.                         }
  427.                     }
  428.                     else
  429.                     {
  430.                         if ( (cmdPBPtr->expectedCount - cmdPBPtr->actualCount) > kUSBMaxBulkTransfer )
  431.                         {
  432.                             usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  433.                         }
  434.                         else
  435.                         {
  436.                             usbPB->usbReqCount     = (cmdPBPtr->expectedCount - cmdPBPtr->actualCount);
  437.                         }
  438.                         
  439.                         usbPB->usbBuffer         = (cmdPBPtr->userBuffer) + (cmdPBPtr->actualCount);
  440.                     }
  441.                     
  442.                     usbPB->usbRefcon         = kBulkOnlyBulkIOComplete;
  443.                     usbPB->usbActCount         = 0;
  444.                     usbPB->usbCompletion     = (USBCompletion)BulkOnlyExecuteCommandCompletion;
  445.                     
  446.                     // Continue a bulk in or out transaction
  447.                     if (bulkPBPtr->flags & kStorageDataIn)
  448.                     {
  449.                         cmdPBPtr->status = USBBulkRead(&bulkPBPtr->usbPB);
  450.                     }
  451.                     else if (bulkPBPtr->flags & kStorageDataOut)
  452.                     {
  453.                         cmdPBPtr->status = USBBulkWrite(&bulkPBPtr->usbPB);
  454.                     }
  455.                 }
  456.                 else
  457.                 {
  458.                     // Bulk transfer is done, get the Command Status Wrapper from the device
  459.                     cmdPBPtr->status = ReceiveCSWPacket(&bulkPBPtr->csw, usbPB, kBulkOnlyStatusReceived);
  460.                 }
  461.             }
  462.             else
  463.             {
  464.                 // Either an error occurred on transfer or we did not get all the data we requested.
  465.                 // In either case, this transfer is complete, clean up and return an error to the client.
  466.                 // Check if the bulk endpoint was stalled
  467.                 USBPipeRef pipeRef = 0;
  468.                 
  469.                 if (bulkPBPtr->flags & kStorageDataIn)
  470.                 {
  471.                     pipeRef = GetBulkInPipeRef();
  472.                 }
  473.                 else if (bulkPBPtr->flags & kStorageDataOut)
  474.                 {
  475.                     pipeRef = GetBulkOutPipeRef();
  476.                 }
  477.                 else
  478.                 {
  479.                     pipeRef = GetInterfaceRef();
  480.                 }
  481.                 
  482.                 cmdPBPtr->status = GetStatusEndpointStatus( usbPB, pipeRef, (USBCompletion) BulkOnlyExecuteCommandCompletion,(Ptr) bulkPBPtr->GetStatusBuffer, kBulkOnlyCheckBulkStall);
  483.             }
  484.         }
  485.         break;
  486.  
  487.         case kBulkOnlyCheckBulkStall:
  488.         {
  489.             // Check to see if the endpoint was stalled
  490.             if ( (bulkPBPtr->GetStatusBuffer[0] & 1) == 1 )
  491.             {
  492.                 USBPipeRef pipeRef = 0;
  493.                 
  494.                 if (bulkPBPtr->flags & kStorageDataIn)
  495.                 {
  496.                     pipeRef = GetBulkInPipeRef();
  497.                 }
  498.                 else if (bulkPBPtr->flags & kStorageDataOut)
  499.                 {
  500.                     pipeRef = GetBulkOutPipeRef();
  501.                 }
  502.                 else
  503.                 {
  504.                     pipeRef = GetInterfaceRef();
  505.                 }
  506.                 
  507.                 cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, pipeRef, (USBCompletion) BulkOnlyExecuteCommandCompletion, kBulkOnlyClearBulkStall);
  508.             }
  509.             else
  510.             {
  511.                 // If the endpoint was not stalled, attempt to get the CSW
  512.                 cmdPBPtr->status = ReceiveCSWPacket(&bulkPBPtr->csw, usbPB, kBulkOnlyStatusReceived);
  513.             }
  514.         }
  515.         break;
  516.         
  517.         case kBulkOnlyClearBulkStall:
  518.         {
  519.             // The pipe was stalled and an attempt to clear it was made
  520.             // Try to get the CSW.  If the pipe was not successfully cleared, this will also
  521.             // set off a device reset sequence
  522.             cmdPBPtr->status = ReceiveCSWPacket(&bulkPBPtr->csw, usbPB, kBulkOnlyStatusReceived);
  523.         }
  524.         break;
  525.         
  526.         case kBulkOnlyStatusReceived:
  527.         {
  528.             // Bulk transfer is done, get the Command Status Wrapper from the device
  529.             if (usbPB->usbStatus != noErr)
  530.             {
  531.                 // An error occurred trying to get the first CSW, we should check and clear the stall,
  532.                 // and then try the CSW again
  533.                 cmdPBPtr->status = ReceiveCSWPacket(&bulkPBPtr->csw, usbPB, kBulkOnlyStatusReceived2ndTime);
  534.             }
  535.             else 
  536.             {
  537.                 // Process the CSW and determine appropriate response
  538.                 if (( bulkPBPtr->csw.cswTag == bulkPBPtr->cbw.cbwTag) && ( bulkPBPtr->csw.cswStatus == kCSWCommandPassedError ))
  539.                 {
  540.                     // The device reports no error on the command, and the command has
  541.                     // the same tag as the command that was sent, check to make sure all data was retrieved
  542.                     if (cmdPBPtr->actualCount == cmdPBPtr->expectedCount )
  543.                     {
  544.                         // We were able to get all the data for the device
  545.                         cmdPBPtr->status = noErr;
  546.                     }
  547.                     else
  548.                     {
  549.                         // An error occurred and we did not get all the data
  550.                         cmdPBPtr->status = kUSBPipeStalledError;
  551.                     }
  552.                 }
  553.                 else
  554.                 {
  555.                     // The device reported an error on the command
  556.                     // report an error to the client
  557.                     cmdPBPtr->status = kUSBPipeStalledError;
  558.                 }
  559.             }
  560.         }
  561.         break;
  562.         
  563.         case kBulkOnlyStatusReceived2ndTime:
  564.         {
  565.             // Second try for the CSW is done, if an error occurred, reset device.
  566.             if (usbPB->usbStatus != noErr)
  567.             {
  568.                 cmdPBPtr->status = BulkDeviceReset(usbPB);
  569.             }
  570.             else
  571.             {
  572.                 cmdPBPtr->status = kUSBInternalErr;
  573.             }
  574.         }
  575.         break;
  576.             
  577.         case kBulkOnlyResetCompleted:
  578.         {
  579.             cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, GetBulkInPipeRef(), (USBCompletion) BulkOnlyExecuteCommandCompletion, kBulkOnlyClearBulkInCompleted);
  580.         }
  581.         break;
  582.  
  583.         case kBulkOnlyClearBulkInCompleted:
  584.         {
  585.             cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, GetBulkOutPipeRef(), (USBCompletion) BulkOnlyExecuteCommandCompletion, kBulkOnlyClearBulkOutCompleted);
  586.         }
  587.         break;
  588.         
  589.         case kBulkOnlyClearBulkOutCompleted:
  590.         {
  591.             cmdPBPtr->actualCount =    0;
  592.             cmdPBPtr->status = kUSBInternalErr;
  593.         }
  594.         break;
  595.         
  596.         default:
  597.         {
  598.             cmdPBPtr->actualCount =    0;
  599.             cmdPBPtr->status = kUSBInternalErr;
  600.         }
  601.         break;
  602.     }
  603.     
  604.     if ( cmdPBPtr->status != kRequestPending )
  605.     {
  606.         bulkPBPtr->busy = false;
  607.         if(cmdPBPtr->completionProc != nil)
  608.         {
  609.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  610.         }
  611.     }
  612. }
  613.  
  614.  
  615.  
  616.